﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UniRlv.COL;

namespace UniRlv.UI.CodeLook
{
    public static class CodePrcUtility
    {
        public static List<CodeInfo> arrCode1;
        public static List<CodeInfo> arrCode2;
        public static List<CodeInfo> arrCode3;
        public static List<CodeInfo> arrCode4;
        public static ProductionTask CurTask;

        #region 其他辅助

        /// <summary>
        /// 根据一次扫描序号查找码信息
        /// </summary>
        /// <param name="stCode"></param>
        /// <returns></returns>
        public static CodeInfo FindCode(string code)
        {
            foreach (CodeInfo item in arrCode1)
            {
                if (item.code.Equals(code))
                {
                    return item;
                }
            }

            foreach (CodeInfo item in arrCode2)
            {
                if (item.code.Equals(code))
                {
                    return item;
                }
            }

            foreach (CodeInfo item in arrCode3)
            {
                if (item.code.Equals(code))
                {
                    return item;
                }
            }

            foreach (CodeInfo item in arrCode4)
            {
                if (item.code.Equals(code))
                {
                    return item;
                }
            }

            return null;
        }

        /// <summary>
        /// 获取顶级包装对应各级包装层次的比例:ratio44,ratio43,ratio42,ratio41
        /// 比如1:20，则返回 1和20
        /// 1:2:4:40，则返回1/2/4/40
        /// </summary>
        /// <returns></returns>
        public static int[] GetCurRatios()
        {
            string ratio = CurTask.tagRatio;
            return AppHelper.GetRatios(ratio);
        }

        /// <summary>
        /// 四级关联的各级包装数量顺序ratio43,ratio32,ratio21
        /// 三级关联的各级包装数量顺序ratio32,ratio21
        /// 二级关联的各级包装数量顺序ratio21
        /// </summary>
        /// <returns></returns>
        public static int[] GetCurLevelRatios()
        {
            string ratio = CurTask.tagRatio;
            return AppHelper.GetLevelRatios(ratio);
        }

        /// <summary>
        ///  获取各工位一级码比例:ratio41, ratio31, ration21
        /// </summary>
        /// <param name="stationNum">工位号</param>
        /// <returns></returns>
        public static int GetStationRatio(int stationNum)
        {
            string ratio = CurTask.tagRatio;
            return AppHelper.GetStationRatio(stationNum, ratio);
        }

        /// <summary>
        ///  获取各工位码数量
        /// </summary>
        /// <param name="stationNum">工位号</param>
        /// <returns></returns>
        public static int GetStationCodeQty(int stationNum)
        {
            switch (stationNum)
            {
                case 1:
                    return arrCode1.Count;
                case 2:
                    return arrCode2.Count;
                case 3:
                    return arrCode3.Count;
                case 4:
                    return arrCode4.Count;
                default:
                    return 0;
            }
        }

        /// <summary>
        /// 根据二次扫描位置查找码集合， pos1 ≤ 二次扫描位置 ＜ pos1 + cnt
        /// </summary>
        /// <param name="pos1"></param>
        /// <param name="cnt"></param>
        /// <returns></returns>
        public static List<CodeInfo> FindArrayByPos2( int pos1, int cnt)
        {
            List<CodeInfo> orderCodes = arrCode2.OrderBy(c => c.serialNumber2).ToList();

            return orderCodes.Skip(pos1).Take(cnt).ToList();

        }

        /// <summary>
        /// 根据一次扫描位置查找码集合， pos1 ≤ 一次扫描位置 ＜ pos1 + cnt
        /// </summary>
        /// <param name="pos1"></param>
        /// <param name="cnt"></param>
        /// <returns></returns>
        public static List<CodeInfo> FindArrayByPos1(int station, int pos1, int cnt)
        {
            switch (station)
            {
                case 1:
                    return arrCode1.Skip(pos1).Take(cnt).ToList();
                case 2:
                    return arrCode2.Skip(pos1).Take(cnt).ToList();
                case 3:
                    return arrCode3.Skip(pos1).Take(cnt).ToList();
                case 4:
                    return arrCode4.Skip(pos1).Take(cnt).ToList();
                default:
                    return null;
            }

        }

        /// <summary>
        /// 根据二次扫描位置查找码集合， pos1 ≤ 二次扫描位置 ＜ tail
        /// </summary>
        /// <param name="pos1"></param>
        /// <returns></returns>
        public static List<CodeInfo> FindArrayByPos2(int pos1)
        {
            return FindArrayByPos2(pos1, arrCode2.Count - pos1);
        }

        /// <summary>
        /// 根据二次扫描序号查找位置，位置从0开始
        /// </summary>
        /// <param name="stCode"></param>
        /// <returns></returns>
        public static int FindCodePos2( CodeInfo stCode)
        {
            if (stCode.serialNumber2<=0)
            {//未二次扫描
                return -1;
            }
	        //根据二次扫描序号对二级码重新排序
            List<CodeInfo> codes = arrCode2.FindAll(c=>c.serialNumber2>0).OrderBy(c=>c.serialNumber2).ToList();
            return codes.IndexOf(stCode);
        }

        /// <summary>
        /// 获取一级码的包装位置，从0开始。。如果不是二次采集，则包装位置和码位置一致，否则包装位置 = 父码的二次序号 X ratio21 + 码位置 % ratio21
        /// </summary>
        /// <param name="stCode"></param>
        /// <returns></returns>
        public static int FindCodeOnePos2(CodeInfo stCode, ref string msg)
        {
            if (stCode.stationNumber != 1)
            {
                msg = "FindCodeOnePos2只适用于一级码";
                return -1;
            }
                
            return FindCodePos(stCode);
        }

        /// <summary>
        /// 根据一次扫描序号查找位置，位置从0开始
        /// </summary>
        /// <param name="stCode"></param>
        /// <returns></returns>
        public static int FindCodePos(CodeInfo stCode)
        {
            IList<CodeInfo> parr;

            switch (stCode.stationNumber)
            {
                case 1:
                    parr = arrCode1;break;
                case 2:
                    parr = arrCode2; break;
                case 3:
                    parr = arrCode3; break;
                case 4:
                    parr = arrCode4; break;
                default:
                    return -1;
            }

                
            return parr.IndexOf(stCode);
            
        }

        /// <summary>
        /// 获取条码
        /// </summary>
        /// <param name="stCode"></param>
        /// <returns></returns>
        public static CodeInfo GetCode(int station, int idx)
        {
            IList<CodeInfo> parr = arrCode1;

            switch (station)
            {
                case 1:
                    parr = arrCode1; break;
                case 2:
                    parr = arrCode2; break;
                case 3:
                    parr = arrCode3; break;
                case 4:
                    parr = arrCode4; break;
            }

            if (idx >= 0 && idx < parr.Count)
            {
                return parr[idx];
            }
            else
            {
                return null;
            }
 
        }


        static CodeInfo FindCodeByPos2(int snPos)
        {
            //根据二次扫描序号对二级码重新排序
            List<CodeInfo> codes = arrCode2.FindAll(c => c.serialNumber2 > 0).OrderBy(c=>c.serialNumber2).ToList();

            return codes[snPos];
        }

        public static CodeInfo GetParent(CodeInfo son, ref string strMsg)
        {
            strMsg = string.Empty;

            if (CurTask.tagLevel <= son.stationNumber)
            {
                strMsg = string.Format("码级别必须小于包装层次：包装层次={0}，码级别={1}", CurTask.tagLevel,
                    son.stationNumber);

                return null;
            }
            int[] ratios = GetCurLevelRatios();
            int idxSon = FindCodePos(son);

            if (idxSon<0)
            {
                strMsg = string.Format("未找到子码");

                return null;
            }

            int idxPrt = idxSon / ratios[CurTask.tagLevel-son.stationNumber-1];

            
            switch (son.stationNumber)
            {
                case 1:
                    if (idxPrt>=arrCode2.Count)
                    {
                        strMsg = string.Format("子码待包装，无法关联到父码：子码序号={0}，已包装数量={1}",
                            idxSon + 1, arrCode2.Count * ratios[0]);

                        return null;
                    }
                    else
                    {
                        return arrCode2[idxPrt];
                    }
                    
                case 2:

                    if (idxPrt >= arrCode3.Count)
                    {
                        strMsg = string.Format("子码待包装，无法关联到父码：子码序号={0}，已包装数量={1}",
                            idxSon + 1, arrCode3.Count * ratios[0]);

                        return null;
                    }
                    else
                    {
                        return arrCode3[idxPrt];
                    }

                case 3:
                    if (idxPrt >= arrCode4.Count)
                    {
                        strMsg = string.Format("子码待包装，无法关联到父码：子码序号={0}，已包装数量={1}",
                            idxSon + 1, arrCode4.Count * ratios[0]);

                        return null;
                    }
                    else
                    {
                        return arrCode4[idxPrt];
                    }
                default:
                    strMsg = string.Format("码级别必须小于4：码级别={0}", son.stationNumber);
                    return null;
            }
        }
        public static CodeInfo GetParent(string son, ref string strMsg)
        {
            CodeInfo ci = FindCode(son);

            if (ci==null)
            {
                strMsg = "码未入库";
                return null;
            }

            return GetParent(ci, ref strMsg);
        }

        /// <summary>
        /// 获取本包装子数据，比如三级关联，获取某二级包装的子码数据
        /// </summary>
        /// <param name="one"></param>
        /// <param name="strMsg"></param>
        /// <returns></returns>
        public static List<CodeInfo> GetLevelSonPackageCodes(CodeInfo parentCode, ref string strMsg)
        {
            int idx = FindCodePos(parentCode);

            if (idx<0)
            {
                strMsg = "码不存在";
                return null;
            }

            int[] ratios = AppHelper.GetLevelRatios(CurTask.tagRatio);
            int ratio32 = 0, ratio21 = 0, ratio43 = 0;

            switch (CurTask.tagLevel)
            {
                case 2:
                    ratio21 = ratios[0];
                    break;
                case 3:
                    ratio32 = ratios[0];
                    ratio21 = ratios[1];

                    break;
                case 4:
                    ratio43 = ratios[0];
                    ratio32 = ratios[1];
                    ratio21 = ratios[2];
                    break;

            }

            switch (parentCode.stationNumber)
            {
                case 1:
                    return new List<CodeInfo>(new CodeInfo[] { parentCode });
                case 2:
                    return FindArrayByPos1(1, idx* ratio21, ratio21);
                case 3:
                    return FindArrayByPos1(2, idx * ratio32, ratio32);
                    
                case 4:
                    return FindArrayByPos1(3, idx * ratio43, ratio43);
                default:
                    return null;
            }
        }


        /// <summary>
        /// 获取整包装数据
        /// </summary>
        /// <param name="one"></param>
        /// <param name="strMsg"></param>
        /// <returns></returns>
        public static List<CodeInfo> GetWholePackageCodes(CodeInfo one, ref string strMsg)
        {
            //获取顶级包装码
            CodeInfo parent = one;

            while (parent.stationNumber!=CurTask.tagLevel)
            {
                parent = GetParent(parent, ref strMsg);

                if (parent == null)
                {
                    return null;
                }
            }

            switch (parent.stationNumber)
            {
                case 1:
                    return new List<CodeInfo>(new CodeInfo[] { one});
                case 2:
                    return GetWholePackageCodes2(one, ref strMsg);
                case 3:
                    return GetWholePackageCodes3(one, ref strMsg);
                case 4:
                    return GetWholePackageCodes4(one, ref strMsg);
                default:
                    return null;
            }
        }


        private static List<CodeInfo> GetWholePackageCodes2(CodeInfo one, ref string strMsg)
        {
            List<CodeInfo> codes = new List<CodeInfo>();
            int ratio21 = GetCurLevelRatios()[CurTask.tagLevel - 2];
            int idx = FindCodePos(one);

            //包装内一级码
            codes.AddRange(FindArrayByPos1(1, idx*ratio21, ratio21));
            codes.Add(one);

            return codes;
        }

        private static List<CodeInfo> GetWholePackageCodes3(CodeInfo one, ref string strMsg)
        {
            List<CodeInfo> codes = new List<CodeInfo>();
            int ratio32 = GetCurLevelRatios()[CurTask.tagLevel - 3];

            int idx = FindCodePos(one);

            //包装内二级码
            List<CodeInfo> codes2 = FindArrayByPos2(idx * ratio32, ratio32);
            foreach (var item in codes2)
            {
                codes.AddRange(GetWholePackageCodes2(item, ref strMsg));
            }
            
            codes.Add(one);

            return codes;
        }

        private static List<CodeInfo> GetWholePackageCodes4(CodeInfo one, ref string strMsg)
        {
            List<CodeInfo> codes = new List<CodeInfo>();
            int ratio43 = GetCurLevelRatios()[0];

            int idx = FindCodePos(one);

            //包装内三级码
            List<CodeInfo> codes3 = FindArrayByPos1(3, idx * ratio43, ratio43);
            foreach (var item in codes3)
            {
                codes.AddRange(GetWholePackageCodes3(item, ref strMsg));
            }

            codes.Add(one);

            return codes;
        }

        public static int GetScanTwiceQty()
        {
            return arrCode2.Count(s=> 
            {
                return s.serialNumber2 > 0;
            });
        }

        public static int GetUnpackQty()
        {
            ProductionTask ws = CurTask;

            if (ws.tagLevel == 1)
            {
                return 0;
            }
            else if (ws.tagLevel == 2)
            {
                int ratio21 =  GetCurRatios()[1];

                if (ratio21*arrCode2.Count > arrCode1.Count)
                {
                    return 0;
                }
                else
	            {
                    return arrCode1.Count - ratio21 * arrCode2.Count;
	            }
                
            }
            else if (ws.tagLevel == 3)
            {
                int ratio31 = GetCurRatios()[2];

                if (ratio31 * arrCode3.Count > arrCode1.Count)
                {
                    return 0;
                }
                else
                {
                    return arrCode1.Count - ratio31 * arrCode3.Count;
                }
            }
            else if (ws.tagLevel == 4)
            {
                int ratio41 = GetCurRatios()[3];

                if (ratio41 * arrCode4.Count > arrCode1.Count)
                {
                    return 0;
                }
                else
                {
                    return arrCode1.Count - ratio41 * arrCode4.Count;
                }
            }
            else
            {
                return 0;
            }
        }

        public static int GetZeroQty()
        {
            ProductionTask ws = CurTask;

            if (ws.tagLevel == 1)
            {
                return 0;
            }
            else
            {
                int ratio21 = GetCurLevelRatios()[ws.tagLevel-2];

                if (ratio21 * arrCode2.Count > arrCode1.Count)
                {
                    return arrCode1.Count % ratio21;
                }
                else
                {
                    return 0;
                }

            }
        }

        public static int GetNormalQty()
        {
            ProductionTask ws = CurTask;

            if (ws.tagLevel == 1)
            {
                return arrCode1.Count;
            }
            else if (ws.tagLevel == 2)
            {
                int ratio21 = GetCurRatios()[1];

                if (ratio21 * arrCode2.Count > arrCode1.Count)
                {
                    return (arrCode1.Count / ratio21) * ratio21;
                }
                else
                {
                    return ratio21 * arrCode2.Count;
                }

            }
            else if (ws.tagLevel == 3)
            {
                int ratio31 = GetCurRatios()[2];

                if (ratio31 * arrCode3.Count > arrCode1.Count)
                {
                    return (arrCode1.Count / ratio31)*ratio31;
                }
                else
                {
                    return ratio31 * arrCode3.Count;
                }
            }
            else if (ws.tagLevel == 4)
            {
                int ratio41 = GetCurRatios()[3];

                if (ratio41 * arrCode4.Count > arrCode1.Count)
                {
                    return (arrCode1.Count / ratio41)*ratio41;
                }
                else
                {
                    return ratio41 * arrCode4.Count;
                }
            }
            else
            {
                return arrCode1.Count;
            }
        }

        //public static List<CodeInfo> GetPackageSons(CodeInfo parent, ref string strMsg)
        //{
        //    strMsg = string.Empty;

        //    if (parent.stationNumber < 2 || parent.stationNumber>CurTask.tagLevel)
        //    {
        //        strMsg = string.Format("码级别必须>1且≤包装层次：包装层次={0}，码级别={1}", CurTask.tagLevel,
        //            parent.stationNumber);

        //        return null;
        //    }


        //}

        #endregion

            /// <summary>
            /// 零箱剩余数据，保证次级定包装达到整包装的零箱，只支持三级和四级关联
            /// </summary>
            /// <param name="msg"></param>
            /// <returns></returns>
        public static bool ZeroRemain(ref string msg)
        {
            int tagLevel = CurTask.tagLevel;

            if (tagLevel < 3)
            {
                msg = "只支持三级和四级关联";
                return false;
            }

            int[] ratios = AppHelper.GetLevelRatios(CurTask.tagRatio);
            int ratio32 = 0, ratio21 = 0, ratio43 = 0;

            switch (CurTask.tagLevel)
            {
                case 3:
                    ratio32 = ratios[0];
                    ratio21 = ratios[1];

                    break;
                case 4:
                    ratio43 = ratios[0];
                    ratio32 = ratios[1];
                    ratio21 = ratios[2];
                    break;
                default:
                    msg = "包装级别不支持：级别=" + tagLevel;
                    return false;

            }

            int nTwo = arrCode1.Count / ratio21;
            nTwo = arrCode2.Count > nTwo ? nTwo : arrCode2.Count;
            try
            {
                arrCode2.RemoveRange(nTwo, arrCode2.Count - nTwo);
            }
            catch (Exception)
            {

            }
               

            for (int i = arrCode1.Count-1; i >= nTwo* ratio21; i--)
            {
                try
                {
                    arrCode1.RemoveAt(i);
                }
                catch (Exception)
                {

                }
                    
            }


            return true;

        }

    }
}
